﻿namespace SenenFernandez.SmartExtensionMethods
{
    using Enum;
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime.InteropServices;
    using System.Text;

    /// <summary>
    /// WPF User32 Interop.
    /// </summary>
    [ComVisibleAttribute(false), System.Security.SuppressUnmanagedCodeSecurity]
    public static class User32
    {
        public const string Path = "user32.dll";

        public delegate bool EnumDelegate(IntPtr handle, int parameter);

        /// <summary>
        /// Retrieves the length, in characters, of the specified window's title bar text (if the window has a title bar). 
        /// If the specified window is a control, the function retrieves the length of the text within the control. However, 
        /// GetWindowTextLength cannot retrieve the length of the text of an edit control in another application.
        /// </summary>
        [DllImport(Path)]
        public static extern int GetWindowTextLength(this IntPtr handle);

        /// <summary>
        /// Copies the text of the specified window's title bar (if it has one) into a buffer. 
        /// If the specified window is a control, the text of the control is copied. However, 
        /// GetWindowText cannot retrieve the text of a control in another application.
        /// </summary>
        [DllImport(Path)]
        public static extern int GetWindowText(this IntPtr handle, StringBuilder stringBuilder, int maxCount);

        /// <summary>
        /// Retrieves a handle to the foreground window (the window with which the user is currently working). 
        /// The system assigns a slightly higher priority to the thread that creates the foreground window than it does to other threads.
        /// </summary>
        [DllImport(Path)]
        public static extern IntPtr GetForegroundWindow();

        /// <summary>
        /// Retrieves a handle to the top-level window whose class name and window name match the specified strings. 
        /// This function does not search child windows. This function does not perform a case-sensitive search.
        /// </summary>
        [DllImport(Path)]
        public static extern IntPtr FindWindow(this string className, string windowName = null);

        /// <summary>
        /// Retrieves a handle to a window whose class name and window name match the specified strings. 
        /// The function searches child windows, beginning with the one following the specified child window. 
        /// This function does not perform a case-sensitive search.
        /// </summary>
        [DllImport(Path, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr FindWindowEx(this IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

        /// <summary>
        /// Determines whether the specified window is minimized (iconic).
        /// </summary>
        [DllImport(Path)]
        public static extern bool IsIconic(this IntPtr handle);

        /// <summary>
        /// Sets the specified window's show state.
        /// </summary>
        [DllImport(Path)]
        public static extern bool ShowWindow(this IntPtr handle, ShowStyle command);

        /// <summary>
        /// Brings the thread that created the specified window into the foreground and activates the window. 
        /// Keyboard input is directed to the window, and various visual cues are changed for the user. 
        /// The system assigns a slightly higher priority to the thread that created the foreground window than it does to other threads.
        /// </summary>
        [DllImport(Path)]
        public static extern bool SetForegroundWindow(this IntPtr handle);

        /// <summary>
        /// Retrieves information about the specified window. 
        /// The function also retrieves the value at the specified offset into the extra window memory.
        /// </summary>
        [DllImport(Path)]
        public static extern WindowStyle GetWindowLong(this IntPtr handle, WindowIndex index);

        /// <summary>
        /// Changes an attribute of the specified window. 
        /// The function also sets the value at the specified offset into the extra window memory.
        /// </summary>
        [DllImport(Path)]
        public static extern int SetWindowLong(this IntPtr handle, WindowIndex index, WindowStyle style);

        /// <summary>
        /// Changes an attribute of the specified window. 
        /// The function also sets the 32-bit (long) value at the specified offset into the extra window memory.
        /// </summary>
        [DllImport(Path)]
        public static extern IntPtr SetWindowPos(this IntPtr handle, int handleInsertAfter, int x, int y, int cx, int cy, PositionFlags flags);

        /// <summary>
        /// Changes the position and dimensions of the specified window.
        /// </summary>
        [DllImport(Path, SetLastError = true)]
        public static extern bool MoveWindow(this IntPtr handle, int x, int y, int width, int height, bool repaint = true);

        /// <summary>
        /// Retrieves the dimensions of the bounding rectangle of the specified window. 
        /// The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.
        /// </summary>
        [DllImport(Path)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowRect(this IntPtr handle, out Rectangle rectangle);

        /// <summary>
        /// Retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window.
        /// </summary>
        [DllImport(Path, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetWindowThreadProcessId(this IntPtr handle, out IntPtr processId);

        /// <summary>
        /// Defines a new window message that is guaranteed to be unique throughout the system. The message value can be used when sending or posting messages.
        /// </summary>
        [DllImport(Path, CharSet = CharSet.Auto)]
        public static extern int RegisterWindowMessage(this string message);

        /// <summary>
        /// Switches focus to the specified window and brings it to the foreground.
        /// </summary>
        [DllImport(Path)]
        public static extern void SwitchToThisWindow(this IntPtr handle, bool altTab);

        /// <summary>
        /// Retrieves a handle to the desktop window.
        /// </summary>
        /// <returns></returns>
        [DllImport(Path, SetLastError = false)]
        public static extern IntPtr GetDesktopWindow();

        /// <summary>
        /// Enables or disables mouse and keyboard input to the specified window or control.
        /// </summary>
        [DllImport(Path)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnableWindow(this IntPtr handle, bool enable);

        /// <summary>
        /// Moves the cursor to the specified screen coordinates.
        /// </summary>
        [DllImport(Path)]
        public static extern bool SetCursorPos(int x, int y);

        /// <summary>
        /// Synthesizes mouse motion and button clicks.
        /// </summary>
        public static void MouseEvent(this MouseEventFlags flags)
        {
            mouse_event((uint)flags);
        }

        /// <summary>
        /// The mouse_event function synthesizes mouse motion and button clicks.
        /// </summary>
        [DllImport(Path),
         SuppressMessage("Tiobe.StyleCopRules.TiobeAnalyzer", "TI3107:IdentifiersShouldNotContainUnderscores"),
         SuppressMessage("Tiobe.StyleCopRules.TiobeAnalyzer", "TI3102:IdentifiersShouldHaveCorrectCasing")]
        public static extern void mouse_event(this uint flags, uint x = 0, uint y = 0, uint data = 0, uint extraInfo = 0);

        /// <summary>
        /// Determines the visibility state of the specified window.
        /// </summary>
        [DllImport(Path)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool IsWindowVisible(this IntPtr handle);

        /// <summary>
        /// Enumerates all top-level windows associated with the specified desktop.
        /// It passes the handle to each window, in turn, to an application-defined callback function.
        /// </summary>
        [DllImport(Path)]
        public static extern bool EnumDesktopWindows(this IntPtr desktopHandle, EnumDelegate callback, IntPtr parameter);

        /// <summary>
        /// Retrieves a handle to the display monitor that has the largest area
        /// of intersection with the bounding rectangle of a specified window.
        /// </summary>
        [DllImport(Path, ExactSpelling = true)]
        public static extern IntPtr MonitorFromWindow(this IntPtr handle, int flags = 0);

        [DllImport(Path)]
        public static extern bool SetWindowPlacement(this IntPtr handle, [In] ref WindowPlacement windowPlacement);

        /// <summary>
        /// Retrieves the show state and the restored, minimized, and maximized positions of the specified window.
        /// </summary>
        [DllImport(Path)]
        public static extern bool GetWindowPlacement(this IntPtr handle, out WindowPlacement windowPlacement);
    }
}